
include('entity');
include('physicalentity');
include('spacebackdrop');
include('physics.engine');
include('box2d');
include('events');


var b2Vec2 = Box2D.Common.Math.b2Vec2;

new_class(
  'Game',
  function(canvas) {
    this._paused = false;
    this._canvas = canvas;
    this._blackholes = [];
    this._entities = [];

    this.physics = new physics.Engine();
  },
  {
    over: function() {
      this.notify('gameOver');
      this.pause();
    },
    pause: function() {
      this.notify('gameWillPause');
      director.stop();
      this._paused = true;
    },
    resume: function() {
      director.start();
      this._paused = false;
      this.notify('gameDidResume');
    },
    start: function() {
      this.notify('gameDidStart');
    },
    addEntity: function(e) {
      this._entities.push(e);
      director.layer("main").addChild(e);
    },
    deleteEntity: function(e) {
      this.physics.delete(e.body);
      var i = this._entities.indexOf(e);
      if (i >= 0)
        this._entities.splice(i, 1);
      e.parentNode.removeChild(e);
    },
    hasEntity: function(e) {
      return this._entities.indexOf(e) != -1;
    },
    addBlackHole: function(bh) {
      if (!bh instanceof BlackHole)
        throw "Invalid parameter: " + bh;
      this._blackholes.push(bh);
      director.layer("main").addChild(bh);
    },
    deleteBlackHole: function(bh) {
      var i = this._blackholes.indexOf(bh);
      if (i >= 0)
        this._blackholes.splice(i, 1);
      bh.parentNode.removeChild(bh);
    },
    getBlackHoles: function() {
      return this._blackholes;
    },
    calculateForces: function() {
      var holes = this.getBlackHoles();
      var holes_len = holes.length;
      for (var i = 0, len = this._entities.length; i < len; i++) {
        var e = this._entities[i];
        for (var j = 0; j < holes_len; j++) {
          var f = holes[j];
          var dx = f.x - e.x;
          var dy = f.y - e.y;
          var d2 = (dx*dx + dy*dy);
          if (d2 != 0) {
            var magnitude = f.force * 1000000 / d2;
            var force = new b2Vec2(dx, dy);
            force.Multiply(magnitude / Math.sqrt(d2));
            e.body._b.ApplyForce(force, new b2Vec2(f.x, f.y));
          }
        }
      }
    },
    calculateBlackHoleCollisions: function() {
      var holes = this.getBlackHoles();
      for (var i = this._entities.length - 1; i >= 0; i--) {
        var e = this._entities[i];
        if (!(e instanceof PhysicalEntity))
          continue;
        for (var j = 0; j < holes.length; j++) {
          var hole = holes[j];
          var dx = hole.x - e.x;
          var dy = hole.y - e.y;
          var d = Math.sqrt(dx*dx + dy*dy);
          if (d < hole.radius) {
            // e should take care of calling Game.deleteEntity
            // on itself when it's ready to be fully removed.
            e.destroy(this);
            // TODO(stevet): Remove this once all entities are set up
            // this.deleteEntity(e);
          }
        }
      }
    },
    stepPhysics: function() {
      this.calculateForces();
      this.physics.step();
      this.calculateBlackHoleCollisions();
    },
  });

add_events_to_class(Game);
